/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/
/*
一、构造方法传入执行器
二、三种状态，一旦状态改变就不可再变，两个实例属性，一个对应成功之后的值，一个表示失败之后的原因
三、resolve 和 reject 用来改变状态并触发回调队列
四、then 方法内部根据当前的状态，来调用用户传入的回调方法
七、then 方法链式调用 、then 的参数回调中可返回普通值与 Promise 对象
八、检测 then 的参数方法的返回值引起循环调用
九、then 链式调用的结果一致性 promise.all promise.resolve p.finally p.catch
十、异常处理 包括执行器与 then 方法的回调参数
*/
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise{

  // 三种状态，一旦状态改变就不可再变
  status = PENDING;

  // 两个实例属性，一个对应成功之后的值，一个表示失败之后的原因
  value = undefined; reason = undefined;

  // PENDING 状态时把回调函数入队
  fulfilledCallbackList = [];
  rejectedCallbackList = [];
  constructor(executor) {
    try{
      executor(this.resolve,this.reject)
    }catch(e){
      // 捕获执行器异常，通过 reject 调用交给 then 方法进一步处理
      this.reject(e.message||e)
    }
  }
  resolve = (value)=>{
    if(this.status!==PENDING) return;
    this.status = FULFILLED
    this.value = value;
    //检查 PENDING 状态时入队的回调函数，非空则依次调用
    while (this.fulfilledCallbackList.length){
      this.fulfilledCallbackList.shift()()
    }
  }
  reject = (reason)=>{
    if(this.status!==PENDING) return;
    this.status = REJECTED;
    this.reason = reason;
    //检查 PENDING 状态时入队的回调函数，非空则依次调用
    while (this.rejectedCallbackList.length){
      this.rejectedCallbackList.shift()();
    }
  }

  then(onFulfilled,onRejected){
    onFulfilled = onFulfilled?onFulfilled:v=>v;
    onRejected = onRejected?onRejected:r=>{throw r};
    // then 方法链式调用
    const thenPromise = new MyPromise((thenResolve,thenReject)=>{
      // 异步执行以下逻辑，目的是等待 thenPromise 值被填充
      setTimeout(()=>{
        try{
          switch (this.status){
            // then 方法内部根据 status 的值调用传入的方法
            case FULFILLED:
              // then 的参数回调中可返回普通值与 Promise 对象
              const fulfillRet =  onFulfilled(this.value);
              this.handleThenCallbackRet(thenPromise,fulfillRet,thenResolve,thenReject);
              break;
            case REJECTED:
              // then 的参数回调中可返回普通值与 Promise 对象
              const rejectRet = onRejected(this.reason);
              this.handleThenCallbackRet(thenPromise,rejectRet,thenResolve,thenReject);
              break;
            case PENDING:
              this.fulfilledCallbackList.push(()=>{
                try{
                  const fulfillRet =  onFulfilled(this.value);
                  this.handleThenCallbackRet(thenPromise,fulfillRet,thenResolve,thenReject);
                }catch (e){thenReject(e.message||e)}
              });
              this.rejectedCallbackList.push(()=>{
                try{
                  const rejectRet = onRejected(this.reason);
                  this.handleThenCallbackRet(thenPromise,rejectRet,thenResolve,thenReject);
                }catch (e){thenReject(e.message||e)}
              });
              break;
          }
        }catch(e){
          // 捕获用户传入的方法异常，通过 reject 调用交给 then 方法进一步处理
          thenReject(e.message||e)
        }
      },5)
    })
    return thenPromise;
  }

  finally(callback){
    console.log('finally ru  n')
    return this.then((value)=>{
      console.log('value in finally then',value)
      // promise 结果穿透处理，用户 callback 返回值的处理
      return MyPromise.resolve(callback()).then(()=>value)
    },(reason)=>{
      console.log('value in finally then')
      // 可以预见，finally 中如果用户的回调方法：callback 返回的是 promise，那么此 promise 结果将会丢弃
      return MyPromise.resolve(callback()).then(null,()=>reason)
    })
  }

  catch(callback){
    return this.then(null,(reason)=>{
      callback(reason)
    })
  }

  static all(promises){
    const result=[];
    let i=0;// 结果记数器，列表任务全部完成后再 resolve
    return new MyPromise((resolve,reject)=>{
      for (let i = 0; i < promises.length; i++) {
        if(promises[i] instanceof MyPromise){
          promises[i].then(value=>{
            addResult(i,value);
          },error=>{
            // 一旦有任务失败，则整个任务标记失败
            reject(error);
          })
        }else{
          addResult(i,promises[i]);
        }
      }
      function addResult(idx,value){
        result[idx] = value;
        i++;
        if(i===promises.length){
          resolve(result);
        }
      }
    })
  }

  /**
   * 将参数转化为 promise 对象
   * @param value 任意值
   */
  static resolve(value){
    if(value instanceof MyPromise){
      return value;
    }
    return new MyPromise(resolve=>{
      resolve(value);
    })
  }

  /**
   * 处理 then 参数回调函数中的返回值
   * @param thenPromise then 方法返回的 promise
   * @param thenRet then 方法参数函数的返回值
   * @param thenResolve then 返回 promise 对象中的成功 trigger
   * @param thenReject then 返回 promise 对象中的失败 trigger
   */
  handleThenCallbackRet = (thenPromise,thenRet,thenResolve,thenReject)=>{
    if(thenPromise===thenRet){
      // 如果 then 方法参数函数的返回值与 then 方法返回的 promise 是同一个对象，则报错处理并返回
      return thenReject(new TypeError('循环调用异常'));
    }
    if(thenRet instanceof MyPromise){
      thenRet.then(thenResolve,thenReject);
    }else{
      thenResolve(thenRet);
    }
  }
}

module.exports = MyPromise;